// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include <iostream>

#include "base/android/jni_generator/sample_for_tests.h"

#include "base/android/jni_android.h"
#include "base/android/jni_string.h"
#include "base/android/scoped_java_ref.h"
// Generated file for JNI bindings from C++ to Java @CalledByNative methods.
// Only to be included in one .cc file.
// Name is based on the java file name: *.java -> jni/*_jni.h
#include "jni/SampleForTests_jni.h" // Generated by JNI.

using base::android::AttachCurrentThread;
using base::android::ConvertJavaStringToUTF8;
using base::android::ConvertUTF8ToJavaString;
using base::android::ScopedJavaLocalRef;

namespace base {
namespace android {

    jdouble CPPClass::InnerClass::MethodOtherP0(
        JNIEnv* env,
        const JavaParamRef<jobject>& caller)
    {
        return 0.0;
    }

    CPPClass::CPPClass()
    {
    }

    CPPClass::~CPPClass()
    {
    }

    // static
    bool CPPClass::RegisterJNI(JNIEnv* env)
    {
        return RegisterNativesImpl(env); // Generated in SampleForTests_jni.h
    }

    void CPPClass::Destroy(JNIEnv* env, const JavaParamRef<jobject>& caller)
    {
        delete this;
    }

    jint CPPClass::Method(JNIEnv* env, const JavaParamRef<jobject>& caller)
    {
        return 0;
    }

    void CPPClass::AddStructB(JNIEnv* env,
        const JavaParamRef<jobject>& caller,
        const JavaParamRef<jobject>& structb)
    {
        long key = Java_InnerStructB_getKey(env, structb);
        std::string value = ConvertJavaStringToUTF8(
            env, Java_InnerStructB_getValue(env, structb).obj());
        map_[key] = value;
    }

    void CPPClass::IterateAndDoSomethingWithStructB(
        JNIEnv* env,
        const JavaParamRef<jobject>& caller)
    {
        // Iterate over the elements and do something with them.
        for (std::map<long, std::string>::const_iterator it = map_.begin();
             it != map_.end(); ++it) {
            long key = it->first;
            std::string value = it->second;
            std::cout << key << value;
        }
        map_.clear();
    }

    ScopedJavaLocalRef<jstring> CPPClass::ReturnAString(
        JNIEnv* env,
        const JavaParamRef<jobject>& caller)
    {
        return ConvertUTF8ToJavaString(env, "test");
    }

    // Static free functions declared and called directly from java.
    static jlong Init(JNIEnv* env,
        const JavaParamRef<jobject>& caller,
        const JavaParamRef<jstring>& param)
    {
        return 0;
    }

    static jdouble GetDoubleFunction(JNIEnv*, const JavaParamRef<jobject>&)
    {
        return 0;
    }

    static jfloat GetFloatFunction(JNIEnv*, const JavaParamRef<jclass>&)
    {
        return 0;
    }

    static void SetNonPODDatatype(JNIEnv*,
        const JavaParamRef<jobject>&,
        const JavaParamRef<jobject>&) { }

    static ScopedJavaLocalRef<jobject> GetNonPODDatatype(
        JNIEnv*,
        const JavaParamRef<jobject>&)
    {
        return ScopedJavaLocalRef<jobject>();
    }

} // namespace android
} // namespace base

int main()
{
    // On a regular application, you'd call AttachCurrentThread(). This sample is
    // not yet linking with all the libraries.
    JNIEnv* env = /* AttachCurrentThread() */ NULL;

    // This is how you call a java static method from C++.
    bool foo = base::android::Java_SampleForTests_staticJavaMethod(env);

    // This is how you call a java method from C++. Note that you must have
    // obtained the jobject somehow.
    jobject my_java_object = NULL;
    int bar = base::android::Java_SampleForTests_javaMethod(
        env, my_java_object, 1, 2);

    std::cout << foo << bar;

    for (int i = 0; i < 10; ++i) {
        // Creates a "struct" that will then be used by the java side.
        ScopedJavaLocalRef<jobject> struct_a = base::android::Java_InnerStructA_create(
            env, 0, 1, ConvertUTF8ToJavaString(env, "test").obj());
        base::android::Java_SampleForTests_addStructA(
            env, my_java_object, struct_a.obj());
    }
    base::android::Java_SampleForTests_iterateAndDoSomething(env, my_java_object);
    base::android::Java_SampleForTests_packagePrivateJavaMethod(env,
        my_java_object);
    base::android::Java_SampleForTests_methodThatThrowsException(env,
        my_java_object);
    return 0;
}
